package web

import (
	"fmt"
	"net/http"
	"regexp"
	"strings"
)

// router 路由树
type router struct {
	// 路由树
	trees map[string]*node
}

type NodeOptions func(node *node)

func newRouter() router {
	return router{
		trees: map[string]*node{},
	}
}

func (r *router) Get(path string, handleFunc HandleFunc, midls ...Middleware) {
	r.addRoute(http.MethodGet, path, handleFunc, midls)
}

func (r *router) Post(path string, handleFunc HandleFunc) {
	r.addRoute(http.MethodPost, path, handleFunc, nil)
}

func (r *router) Options(path string, handleFunc HandleFunc) {
	r.addRoute(http.MethodOptions, path, handleFunc, nil)
}

func (r *router) addRoute(method, path string, handleFunc HandleFunc, midls []Middleware) {
	if method == "" {
		panic("请传入非空请求方法")
	}
	if path == "" {
		panic("请传入非空请求路径")
	}

	/**
	  判断路由不为"/"打头， 且结尾不能有"/"
	*/

	if path[0] != '/' {
		panic("路由必须以\"/\"开头")
	}

	if path != "/" && path[len(path)-1] == '/' {
		panic("路由不能以'/' 结尾")
	}
	// 获取根树
	root, ok := r.trees[method]
	if !ok {
		// 初次定义初始化树
		root = &node{path: "/"}
		r.trees[method] = root
	}

	if path == "/" {
		if root.handler != nil {
			panic("web: 路由冲突[/]")
		}
		root.handler = handleFunc
		root.route = "/"
		return
	}

	// 根据 '/' 切割字符串, 且跳过第一个'/'
	path = path[1:]
	segs := strings.Split(path, "/")
	// 开始一段段处理
	for _, s := range segs {
		if s == "" {
			panic(fmt.Sprintf("web: 非法路由。不允许使用 //a/b, /a//b 之类的路由, [%s]", path))
		}
		root = root.childOrCreate(s)
	}
	if root.handler != nil {
		panic(fmt.Sprintf("web: 路由冲突[%s]", path))
	}
	// 定义合法请求方法， 后续实现
	// 由于root 一层层被处理，直到最后for range 循环跑完后
	root.handler = handleFunc
	root.route = path
	if len(root.mdls) == 0 {
		root.mdls = midls
	}
	return
}

func (n *node) childOrCreate(path string) *node {

	if path[0] == ':' {

		_, _, regexpString, isRegexp := n.pathRegexp(path)
		if isRegexp {
			if n.paramChild != nil {
				panic(fmt.Sprintf("不允许重复注册参数路由与正则路由 [%s] 与 [%s]", regexpString, n.paramChild.path))
			}
			n.regexpChild = &node{path: path}
			return n.regexpChild
		} else {
			if n.starChild != nil {
				panic("不允许重复注册通配符匹配与参数匹配")
			}
			n.paramChild = &node{path: path}
			return n.paramChild
		}
	}

	if path == "*" {
		if n.paramChild != nil {
			panic("不允许重复注册通配符匹配与参数匹配")
		}
		if n.starChild == nil {
			n.starChild = &node{path: "*"}
		}
		return n.starChild
	}

	if n.children == nil {
		// 初始化
		n.children = make(map[string]*node)
	}
	grandson, gok := n.children[path]
	if !gok {
		grandson = &node{path: path}
		n.children[path] = grandson
	}
	return grandson
}

// childOf 查找子节点
// 第一个返回值 *node 是命中的节点
// 第二个返回值 bool 是否命中正则参数路由
// 第三个返回值 bool 代表是否是命中参数路由
// 第四个返回值 bool 代表是否命中[正则，参数，通配]
func (n *node) childOf(path string) (*node, bool, bool, bool) {

	if n.children == nil {
		if n.regexpChild != nil {
			compile, _, _, _ := n.pathRegexp(n.regexpChild.path)
			if compile != nil {
				match := compile.Match([]byte(path))
				if match {
					return n.regexpChild, true, false, true
				}
			}
		} else if n.paramChild != nil {
			return n.paramChild, false, true, true
		}
		return n.starChild, false, false, n.starChild != nil
	}
	// 尝试精确匹配
	res, ok := n.children[path]
	if !ok {
		if n.paramChild != nil {
			return n.paramChild, false, true, true
		}
		return n.starChild, false, false, n.starChild != nil
	}
	return res, false, false, ok
}

// pathRegexp 判断路径是否含有正则表达式路径
func (n *node) pathRegexp(path string) (*regexp.Regexp, int, string, bool) {
	regxFirstIndex := strings.Index(path, "(")
	if regxFirstIndex < 0 {
		return nil, 0, "", false
	}
	suspectedRegxString := path[regxFirstIndex:]
	compile, err := regexp.Compile(suspectedRegxString)
	if err != nil {
		panic(fmt.Sprintf("非法正则表达式 [%s] 错误：[%s]", suspectedRegxString, err.Error()))
	}
	return compile, regxFirstIndex, suspectedRegxString, true
}

func (r *router) findRoute(method, path string) (*matchInfo, bool) {
	root, ok := r.trees[method]
	match := &matchInfo{}
	if !ok {
		return nil, false
	}

	if path == "/" {
		match.n = root
		return match, true
	}

	path = strings.Trim(path, "/")
	segs := strings.Split(path, "/")
	var existsStartRoot *node
	var pathParams map[string]string
	for _, seg := range segs {
		child, regexpChild, paramChild, ok := root.childOf(seg)
		if child != nil && child.starChild != nil {
			existsStartRoot = child.starChild
		}
		// 命中了正则
		if regexpChild {
			pathParams = make(map[string]string)
			_, index, _, _ := child.pathRegexp(child.path)
			pathParams[child.path[1:index]] = seg
			match.pathParam = pathParams
		}

		// 命中了路径参数
		if paramChild {
			pathParams = make(map[string]string)
			pathParams[child.path[1:]] = seg
			match.pathParam = pathParams
		}
		if !ok {
			if existsStartRoot != nil {
				match.n = existsStartRoot
				return match, true
			} else {
				return nil, false
			}
		}
		root = child
	}
	match.n = root
	return match, true
}

type matchInfo struct {
	n         *node
	pathParam map[string]string
}

type node struct {
	// 命中的路由
	route string
	// path 路径
	path string
	// children 子节点
	children map[string]*node
	// 通配符节点
	starChild *node
	// 正则路由
	regexpChild *node
	// 参数路由
	paramChild *node
	// handler 处理方法
	handler HandleFunc
	// mdls 子节点中间件
	mdls []Middleware
}
